package com.forever7776.life.web.config.websocket;

import com.alibaba.fastjson.JSONObject;
import com.forever7776.life.core.common.vo.TweetSendVO;
import com.forever7776.life.core.common.vo.TweetsVO;
import com.forever7776.life.core.common.vo.UserBaseInfoVO;
import com.forever7776.life.core.entity.Tweets;
import com.forever7776.life.core.entity.stat.StatTweet;
import com.forever7776.life.core.entity.sys.SysUser;
import com.forever7776.life.core.service.ITweetsService;
import com.forever7776.life.core.service.stat.IStatTweetService;
import com.forever7776.life.core.service.sys.ISysUserService;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import util.RelativeDateFormatUtil;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author kz
 * @date 2018/03/28
 * 控制器
 */
public class InteractiveCtrlHandler extends TextWebSocketHandler {

    private final static Logger logger = LoggerFactory.getLogger(InteractiveCtrlHandler.class);

    @Autowired
    private ITweetsService iTweetsService;
    @Autowired
    private ISysUserService iSysUserService;
    @Autowired
    private IStatTweetService iStatTweetService;

    /**
     * 客户端连接完成之后
     *
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session)
            throws Exception {
        logger.info("==> conn sessionId={} address={}", session.getId(), session.getLocalAddress().toString());
        String channelName = getChannelFromSession(session);
        if (WebSocketChannel.isExistsCtrlChannel(channelName)) {
            logger.info("==> {} already connected not allow connect again", channelName);
            JSONObject eventMessage = new JSONObject();
            eventMessage.put("event", "close");
            eventMessage.put("msg", "已存在连接的控制端");
            TextMessage returnMessage = new TextMessage(eventMessage.toJSONString());
            if (session.isOpen()) {
                session.sendMessage(returnMessage);
            }
            session.close();//关闭当前连接
        } else {
            WebSocketChannel.addCtrlChannel(channelName, session);
            logger.info("==> ctrl channel={} connected success", channelName);
        }
    }

    /**
     * 接收消息处理
     *
     * @param session
     * @param message
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        long begin = System.currentTimeMillis();
        TweetSendVO sendVO = JSONObject.parseObject(message.getPayload(), TweetSendVO.class);
        String t = sendVO.getT();
        String userId = sendVO.getUserId();
        String content = sendVO.getContent();
        logger.info("==> ctrl userId={} sessionId={} content={}", userId, session.getId(), content);
        //转发到大屏消息,默认为控制台传入的消息
        TextMessage forwardMessage = message;
        //返回消息
        TextMessage returnMessage = null;

        try {
            List<WebSocketSession> webSocketSessionList = WebSocketChannel.getAllScreenChannel(t);
            if (CollectionUtils.isEmpty(webSocketSessionList)) {
                JSONObject eventMessage = new JSONObject();

                returnMessage = new TextMessage(eventMessage.toJSONString());
                session.sendMessage(returnMessage);
                logger.info("==> send to error message={}", eventMessage);
                return;
            }

            JSONObject data = new JSONObject();
            Tweets tweets = new Tweets();
            tweets.setUserId(userId);
            tweets.setContent(content);
            iTweetsService.insert(tweets);

            StatTweet stat = new StatTweet();
            stat.setTweetId(tweets.getId());
            iStatTweetService.insert(stat);

            UserBaseInfoVO info = iSysUserService.selectUserBaseInfoById(userId);

            Map<String, Object> map = new HashMap<>();
            map.put("id", tweets.getId());
            map.put("userId", info.getUserId());
            map.put("headimg", info.getHeadimg());
            map.put("username", info.getUsername());
            map.put("nickname", info.getNickname());
            map.put("content", content);
            map.put("insertDate", RelativeDateFormatUtil.format(new Date()));
            data.putAll(map);

            forwardMessage = new TextMessage(data.toString());


            //通知所有大屏
            sendMessageToAllScreen(webSocketSessionList, forwardMessage);

            logger.info("==> send to screen message={}", forwardMessage.getPayload());
        } catch (Exception e) {
            JSONObject eventMessage = new JSONObject();
            eventMessage.put("msg", "服务器异常");
            returnMessage = new TextMessage(eventMessage.toJSONString());
            session.sendMessage(returnMessage);
            logger.error("==> message handler error", e);
        } finally {
            logger.info("==> time={}", System.currentTimeMillis() - begin);
        }
    }


    /**
     * 异常处理
     *
     * @param session
     * @param exception
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        super.handleTransportError(session, exception);
    }

    /**
     * 连接终断
     *
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String channelName = getChannelFromSession(session);
        WebSocketChannel.delCtrlChannel(channelName);
        logger.info("==> ctrl channel={} sessionId={} close", channelName, session.getId());
        super.afterConnectionClosed(session, status);
    }

    private String getChannelFromSession(WebSocketSession session) {
        String channelName = (String) session.getAttributes().get("userId");
        return channelName;
    }


    public void sendMessageToAllScreen(List<WebSocketSession> screeList, TextMessage textMessage) {
        if (CollectionUtils.isEmpty(screeList)) {
            return;
        }
        for (WebSocketSession session : screeList) {
            try {
                if (!session.isOpen()) {
                    continue;
                }
                session.sendMessage(textMessage);
            } catch (IOException e) {
                logger.error("==> send message error", e);
            }
        }
    }
}
